package com.ljf.framework.security.token;

import com.ljf.framework.LjfManager;
import com.ljf.framework.cache.LjfCacheManager;
import com.ljf.framework.context.LjfContextManager;
import com.ljf.framework.context.model.LjfCookie;
import com.ljf.framework.context.model.LjfRequest;
import com.ljf.framework.context.model.LjfResponse;
import com.ljf.framework.context.model.LjfStorage;
import com.ljf.framework.security.LjfSecurityManager;
import com.ljf.framework.util.LjfStringUtil;

/**
 * 说明：token管理类
 *
 * @Auther: lijinfeng
 * @Date: 2023/9/20
 */
public class LjfTokenManager {

    private LjfTokenManager() {
        throw new IllegalStateException("Utility class");
    }


    public static String getTokenValue() {
        // 0. 获取相应对象
        LjfStorage storage = LjfContextManager.getStorage();
        LjfRequest request = LjfContextManager.getRequest();
        LjfTokenConfig config = LjfSecurityManager.getTokenConfig();
        String keyTokenName = LjfTokenConstants.TOKEN_NAME;
        String tokenValue = null;

        // 1. 尝试从Storage里读取
        if (storage.get(splicingKeyJustCreated()) != null) {
            tokenValue = String.valueOf(storage.get(splicingKeyJustCreated()));
        }
        // 2. 尝试从请求体里面读取
        if (tokenValue == null && config.getIsReadBody()) {
            tokenValue = request.getParam(keyTokenName);
        }
        // 3. 尝试从header里读取
        if (tokenValue == null && config.getIsReadHeader()) {
            tokenValue = request.getHeader(keyTokenName);
        }
        // 4. 尝试从cookie里读取
        if (tokenValue == null && config.getIsReadCookie()) {
            tokenValue = request.getCookieValue(keyTokenName);
        }
        // 5. 返回
        return tokenValue;


    }

    /**
     * 在当前会话写入当前TokenValue
     *
     * @param tokenValue token值
     */
    public static void saveTokenValue(String tokenValue) {

        if (LjfStringUtil.isEmpty(tokenValue)) {
            return;
        }

        // 1. 将 Token 保存到 [存储器] 里
        setTokenValueToStorage(tokenValue);

        // 2. 将 Token 保存到 [Cookie] 里
        setTokenValueToCookie(tokenValue, (int) LjfTokenManager.getLjfTokenConfig().getTimeout());

        // 3. 将 Token 保存到 [响应头] 里
        setTokenValueToResponseHeader(tokenValue);

    }

    /**
     * 将 Token 写入到 [响应头] 里
     *
     * @param tokenValue token值
     */
    public static void setTokenValueToResponseHeader(String tokenValue) {
        String tokenName = LjfTokenConstants.TOKEN_NAME;
        LjfResponse response = LjfContextManager.getResponse();
        response.setHeader(tokenName, tokenValue);
        response.addHeader(LjfResponse.ACCESS_CONTROL_EXPOSE_HEADERS, tokenName);
    }

    /**
     * 将 Token 保存到 [Storage] 里
     *
     * @param tokenValue token值
     */
    public static void setTokenValueToStorage(String tokenValue) {
        // 1. 将token保存到[存储器]里
        LjfStorage storage = LjfContextManager.getStorage();

        // 3. 写入 (无前缀)
        storage.set(splicingKeyJustCreated(), tokenValue);
    }

    /**
     * 将 Token 保存到 [Cookie] 里
     *
     * @param tokenValue    token值
     * @param cookieTimeout Cookie存活时间(秒)
     */
    public static void setTokenValueToCookie(String tokenValue, int cookieTimeout) {
        LjfCookie cookie = new LjfCookie()
                .setName(LjfTokenConstants.TOKEN_NAME)
                .setValue(tokenValue)
                .setMaxAge(cookieTimeout)
                .setDomain("")
                .setPath("")
                .setSecure(Boolean.TRUE)
                .setHttpOnly(Boolean.TRUE)
                .setSameSite("Strict");
        LjfContextManager.getResponse().addCookie(cookie);
    }

    /**
     * 根据 userId 生成 token
     *
     * @param userId
     * @return
     */
    public static String createToken(Long userId) {
        return createToken(userId, true);
    }


    /**
     * 根据 userId 生成 token
     *
     * @param userId  用户id
     * @param isCache 是否缓存
     * @return token
     */
    public static String createToken(Long userId, Boolean isCache) {
        String token = LjfManager.getLjfTokenService().createToken(userId);
        // 缓存 token - userId 对应关系
        if (!LjfSecurityManager.isLogin())
            // 没有登录则第一次登录，先缓存到本地
            LjfCacheManager.set(LjfTokenConstants.JUST_CREATED + token, userId.toString(), LjfTokenManager.getLjfTokenConfig().getTimeout());

        if (isCache) {
            LjfCacheManager.set(LjfTokenConstants.TOKEN_PREFIX + token, userId.toString(), LjfTokenManager.getLjfTokenConfig().getTimeout());
        }
        return token;
    }

    /**
     * 如果token为本次请求新创建的，则以此字符串为key存储在当前request中
     *
     * @return key
     */
    private static String splicingKeyJustCreated() {
        return LjfTokenConstants.JUST_CREATED;
    }

    /**
     * 根据token获取用户ID
     *
     * @param token
     * @return
     */
    public static Long getUserIdByToken(String token) {
        return LjfManager.getLjfTokenService().getUserIdByToken(token);
    }

    /**
     * 校验token
     *
     * @param token
     */
    public static void checkToken(String token) {
        LjfManager.getLjfTokenService().checkToken(token);
    }

    /**
     * 获取请求getToken
     */
    public static LjfToken getLjfToken() {
        LjfToken info = new LjfToken();
        info.tokenName = LjfTokenConstants.TOKEN_NAME;
        info.tokenValue = getTokenValue();
        info.isLogin = LjfSecurityManager.isLogin();
        info.loginId = getLoginIdDefaultNull();
        info.loginType = getLoginType();
        info.tokenTimeout = getTokenTimeout();
        info.sessionTimeout = getSessionTimeout();
        info.tokenSessionTimeout = getTokenSessionTimeout();
        info.tokenActivityTimeout = getTokenActivityTimeout();
        info.loginDevice = getLoginDevice();
        return info;
    }

    private static String getLoginDevice() {
        return null;
    }

    private static long getTokenActivityTimeout() {
        return 0;
    }

    private static long getTokenSessionTimeout() {
        return 0;
    }

    private static long getSessionTimeout() {
        return 0;
    }

    private static long getTokenTimeout() {
        return 0;
    }

    private static String getLoginType() {
        return null;
    }

    private static Object getLoginIdDefaultNull() {
        return null;
    }

    /**
     * token 配置 Bean
     */
    private volatile static LjfTokenConfig ljfTokenConfig;

    public static LjfTokenConfig getLjfTokenConfig() {
        if (ljfTokenConfig == null) {
            synchronized (LjfTokenManager.class) {
                if (ljfTokenConfig == null) {
                    setLjfTokenConfig(new LjfTokenConfig());
                }
            }
        }
        return ljfTokenConfig;
    }
    public static void setLjfTokenConfig(LjfTokenConfig config) {
        LjfTokenManager.ljfTokenConfig = config;
    }

}
